package xFGE.Loader
{	
	import flash.events.*;
	import flash.net.URLLoader;
	import flash.net.URLRequest;
	import flash.utils.*;
	
	
//	import BaseLib.Loader.xLoaderProgressEvent;

	
	[Event(name="single_completed",type="xFGE.Loader.xLoaderEvent")]
	[Event(name="single_progress",type="xFGE.Loader.xLoaderEvent")]
	[Event(name="batch_completed",type="xFGE.Loader.xLoaderEvent")]
	[Event(name="batch_progress",type="xFGE.Loader.xLoaderEvent")]
	public class xLoader extends EventDispatcher
	{
		/** 加载器状态*/
		// 忙碌
		public static const LOADER_STATUS_BUSY:String = "busy";
		//空闲 
		public static const LOADER_STATUS_IDLE:String ="idle";
		//完成
		public static const LOADER_STATUS_COMPLETE:String = "complete";
		//出错
		public static const LOADER_STATUS_ERROR:String = "error";
		/** 加载器类型 */
		//图片加载器
		public static const LOADER_TYPE_IMGE:String = "imge";
		//swf加载器
		public static const LOADER_TYPE_SWF:String = "swf";
		//二进制加载器
		public static const LOADER_TYPE_BYTE:String = "byte";
		
		/** 最大线程数 */
		public static const LOADER_MAX_THREAD:int = 7; 
		
		/**	最大尝试次数 */
		public static const LOADER_RETRY_TIME:int = 3;
		
		/** 实例 */
		private static var _myInstance:xLoader;
		
		/** 已加载字节数 */
		private var _loadedBytes:int;
		
		/** 共加载字节数 */
		private var _loadedTotalBytes:int;
		
		/** 加载资源总个数 */
		private var _loadedTotalWeight:int;
		
		/** 加载百分比进度 */
		private var _loadedPrecent:Number;
		
		/** 加载即时速度 */
		private var _loadedSpeed:Number;
		
		/** 加载平均速度 */
		private var _loadedAvgSpeed:Number;
		
		/** 加载时间 */
		private var _loadedTime:Number;
		
		/** 记录最后计时时间 */
		private var _lastTime:int;
		
		/** 记录最后加载字节数　*/
		private var _lastLoadedBytes:int;
		
		/** 加载器详细信息 */
		private var _loaderStateInfo:String;
		
		/** 是否多线程下载 */
		private var _isMulit:Boolean = false;
		
		/** 是否允许有加载失败资源 */
		private var _isAllowError:Boolean = true;
	
		/** 加载线程池 */
		private var _loaderThreadPool : Array;
		
		/** 加载池 */
		private var _loadPool:Array;
		
		/** 下载失败的资源列表 */
		private var _errorList:Array;
		
		/** 资源列表 */
		private var _resourceList:Dictionary;
		
		/** xloder状态 */
		private var _state:String;
		
		
		/** url记录 */
		private var _urlLog:Array;
		/** 批次记录 */
		private var _batchRes:Array;
		
		
		
		public function xLoader()
		{
			//TODO: implement function
			if(_myInstance){
				throw new Error("请用getInstance获取实例");
			}
			
			_state = xLoader.LOADER_STATUS_IDLE;
			_loadPool = new Array();
			_loaderThreadPool = new Array();
			_resourceList = new Dictionary();
			_errorList = new Array();
			_urlLog = new Array();
			//_batchRes = new Array();
		}
		
		
		/**
		 * 加载 
		 * @param type 资源类型
		 * @param name 资源名称
		 * @param path 资源url
		 * @param isCallBack 改资源加载完成时，是否需要回调
		 * @param swfClassName 读取swf时，swf绑定的类名，如果无绑定为null
		 * 
		 */
		public function Load(type:String,name:String,path:String,isAllowSameName:Boolean=false,isCallBack:Boolean=false,swfClassName:String=null):void
		{
			//排除同资源重复加载
			if(!isAllowSameName){
				for each(var resName:String in _urlLog){
					if(resName == name) return;
				}
			}
			_urlLog.push(name);
			// 压栈到加载池
			_loadPool .push(new ResourceObj(name,type,new URLRequest(path),isCallBack,swfClassName));
			
		}
		
		/**
		 * 资源配置文件 
		 * @param xmlConfig xml文件
		 * 
		 */
		public function LoadConfig(urlConfig:String):void
		{
			var loader:URLLoader = new URLLoader();
			loader.addEventListener(Event.COMPLETE,_onConfigComplete);
			loader.load(new URLRequest(urlConfig));
		}
		
		/**
		 *	开始批量载入资源 
		 * 
		 */
		public function Start():void
		{
			if(_loadPool.length == 0 || _state != xLoader.LOADER_STATUS_IDLE) return;
			_state = xLoader.LOADER_STATUS_BUSY;
			// 记录总共要加载个数
			//_loadedTotalWeight = _loadPool.length;
			//if(_batchRes.length != 0) _batchRes.splice(0,_batchRes.length);
			_batchRes = _loadPool.concat();
			// 记录开始加载时间
			_lastTime = getTimer();
			for(var i:int=0;i<xLoader.LOADER_MAX_THREAD;i++)
			 _loadNext();
			 
		}
		
		/**
		 * 获取资源 
		 * @param key 资源名
		 * @return  返回资源数据
		 * 
		 */
		public function GetResouces(key:String):*
		{
			var resource:ResourceObj;
			if(_resourceList[key] != undefined){
				resource = (_resourceList[key] as ResourceObj);
			}
			if(!resource){
				//trace("资源文件:"+key+"不存在或者加载失败");
//				throw("资源文件:"+key+"不存在或者加载失败");
				return null;
			}
			/* if(resource.getResourceFun != null)return resource.getResourceFun();
			else return resource.content; */
			return resource.content;
		}
		/**
		 * 手动添加资源入资源库内
		 * 
		 * @param resource    资源对象
		 */
		public function AddResource(resource:ResourceObj): void
		{
			_resourceList[resource.name] = resource
		} 
		/**
		 * 获取单例
		 * @return 
		 * 
		 */
		public static function getInstance():xLoader
		{
			if(!_myInstance) _myInstance = new xLoader();
			return _myInstance;
		}
		
	
		/**
		 * 精确小数点后位置
		 * @param raw 要精确的数字
		 * @param decimals 小数点后的位数
		 * @return 
		 * 
		 */
		public static function truncateNumber(raw : Number, decimals :int =2) : Number {
            var power : int = Math.pow(10, decimals);
           return Math.round(raw * ( power )) / power;
        }
        
        /**
         * 深复制object 
         * @param clone
         * @return 
         * 
         */
        public static function deepClone(clone:Object):*
        {
        	var obj:ByteArray = new ByteArray();
        	obj.writeObject(clone);
        	obj.position =0;
        	return obj.readObject();
        }
        
        /**
         * 配置文件载入完成 
         * @param eveObj
         * 
         */
        private function _onConfigComplete(eveObj:Event):void
        {
        	var configXml:XML;
        	try{
        		configXml = new XML(eveObj.target.data);
        	}catch(e:SecurityError){
        		trace("错误xml文件");
        		trace(e.message);
        		return;
        	}
        	var resource:XMLList = configXml.child("Resource");
        	// 分析xml配置
        	for each(var element:XML in resource.elements()){
        		var type:String;
        		trace(element.localName());
        		switch(element.localName()){
        			case xLoader.LOADER_TYPE_IMGE:
        				type = element.localName();
        			break;
        			case xLoader.LOADER_TYPE_SWF:
        				type = element.localName();
        			break;
        			case xLoader.LOADER_TYPE_BYTE:
        				type = element.localName();
        			break;
        			default:
        				trace("未知资源类型");
        			continue;
        		}
        		
        		Load(type,element.@name,element.@url,false,(element.@callback)=="true"?true:false,element.@classname);
        	}
        	Start();
        	return;
        }
       
        /**
		 * 开始载入 
		 * @param eveObj
		 * 
		 */
		private function _onStart(eveObj:Event):void
		{
			//trace("open");
			
			return;
		}
		
		/**
		 * 完成事件处理
		 * @param eveObj
		 * 
		 */
		private function _onComplete(eveObj:Event):void
		{
			
			//单一任务完成
			var Loader:LoaderBase = eveObj.currentTarget as LoaderBase;
			//trace(Loader.resourceObj.name);
			Loader.resourceObj.content = Loader.content;
			AddResource( Loader.resourceObj);
			//_onProgress(null);
			if(Loader.resourceObj.isCallBack) //该资源如有设置载入完成后回调，则回调
			{
				var event:xLoaderEvent = new xLoaderEvent(xLoaderEvent.SINGLE_COMPLETED);
				event.resourceObj = Loader.resourceObj;
				dispatchEvent(event);
			}
			
			//读取下个资源
			_loadNext(eveObj.currentTarget as LoaderBase);
			//判断是否全部完成
			if(!_loadPool.length && _isAllDone()){
				//trace("all complete");
				_calPrecent(Loader.resourceObj,true);
				_removeAllLoader();
				// 是否允许有错误加载资源
				if(!_isAllowError && _errorList.length)return;
				_state = xLoader.LOADER_STATUS_IDLE;
				var eve:xLoaderEvent = new xLoaderEvent(xLoaderEvent.BATCH_COMPLETED);
				dispatchEvent(eve);
			}
			return;
		}
		/**
		 * 网络状态事件
		 * @param eveObj 
		 * 
		 */
		private function _onHttpStatus(eveObj:HTTPStatusEvent):void
		{
			var loader:LoaderBase = eveObj.currentTarget as LoaderBase;
			var errorObj:ResourceObj = loader.resourceObj;
			_errorResource(errorObj,eveObj.currentTarget as LoaderBase);
			return;
		}
		
		/**
		 * 文件io出错 
		 * @param eveObj
		 * 
		 */
		private function _onIOError(eveObj:IOErrorEvent):void
		{
			var loader:LoaderBase = eveObj.currentTarget as LoaderBase;
			var errorObj:ResourceObj = loader.resourceObj;
			_errorResource(errorObj,eveObj.currentTarget as LoaderBase);
			return;
		}
		
		/**
		 * 总加载过程处理
		 * @param eveObj
		 * 
		 */
		private function _onProgress(eveObj:Event):void
		{
			//更新数据 
			var Loader:LoaderBase = eveObj.currentTarget as LoaderBase;
			//单文件进度事件
			dispatchEvent(new xLoaderEvent(xLoaderEvent.SINGLE_PROGRESS));
			_calPrecent(Loader.resourceObj);
			return;
		}
		
		/**
		 * 计算总加载进度 
		 * @param resourceObj 单个资源
		 * 
		 */
		private function _calPrecent(resourceObj:ResourceObj,isAllDone:Boolean=false):void
		{
			if(_batchRes.length == 0)return;
			if(!isAllDone){
				_loadedPrecent = 0;
				var batchDone:Boolean = true;
				var weight:Number = xLoader.truncateNumber( 1/_batchRes.length,2);
				for each(var res:ResourceObj in _batchRes){
					if(res.loadedPresent != 1) batchDone = false;
					_loadedPrecent+= xLoader.truncateNumber(res.loadedPresent * weight,3);
					_loadedPrecent = xLoader.truncateNumber(_loadedPrecent,3);				
				}
				if(batchDone)_loadedPrecent = 1;
			}
			var eve:xLoaderEvent = new xLoaderEvent(xLoaderEvent.BATCH_PROGRESS);
			eve.LoadedPrecent = _loadedPrecent;
			dispatchEvent(eve);
		}
		/**
		 * 错误加载处理 
		 * @param errorResource 错误加载资源
		 * 
		 */
		private function _errorResource(errorResource:ResourceObj,curLoader:LoaderBase):void 
		{
			if(errorResource.retry >= xLoader.LOADER_RETRY_TIME){//超出尝试次数，标记失败，并保存
				errorResource.failed = true;
				trace(errorResource.name+"超出重试次数，载入失败");
				_errorList.push(errorResource);	
				//当加载信息在超出重试次数后，加载器是属于完成状态
				curLoader.loaderStatus = xLoader.LOADER_STATUS_COMPLETE;
				
				// 读取下一个资源
				_loadNext(curLoader);
				// 判断是否全部完成
				if(_loadPool.length == 0 && _isAllDone()){
					//trace("all done");
					_removeAllLoader();
					_state = xLoader.LOADER_STATUS_IDLE;
					if(_isAllowError){
						this.dispatchEvent(new xLoaderEvent(xLoaderEvent.BATCH_COMPLETED));
					}
				}
				
			}else{
				var key:int = _loadPool.indexOf(errorResource);
				if(key == -1){
					errorResource.retry++;
					trace(errorResource.name + "正在尝试重试第"+errorResource.retry +"次....");
					//_loadPool.push(errorResource);
					curLoader.Load(errorResource);
				} 
			}
		}
		/**
		 * 检查是否全部加载器完成加载 
		 * @return 
		 * 
		 */
		private function _isAllDone():Boolean
		{
			var key:LoaderBase;
			for each(key in _loaderThreadPool){
				if(key.loaderStatus != xLoader.LOADER_STATUS_COMPLETE) return false;
			}
			return true;
		}
		/**
		 * 增加线程加载器 
		 * @param type 增加加载器类型
		 * 
		 */
		private function _addLoader(type:String):LoaderBase
		{
			if(_loaderThreadPool.length >= xLoader.LOADER_MAX_THREAD)return null;
			var loader:LoaderBase;
			switch(type){
				case xLoader.LOADER_TYPE_IMGE:
					loader = new ImageLoader();
				break;
				case xLoader.LOADER_TYPE_SWF:
					loader = new SWFLoader();
				break;
			} 
			loader.addEventListener(Event.OPEN,_onStart);
			loader.addEventListener(Event.COMPLETE,_onComplete);
			loader.addEventListener(ProgressEvent.PROGRESS,_onProgress);
			loader.addEventListener(HTTPStatusEvent.HTTP_STATUS,_onHttpStatus);
			loader.addEventListener(IOErrorEvent.IO_ERROR,_onIOError);
			
			_loaderThreadPool.push(loader);
			return loader;
			
		}
		

		/**
		 * 移除线程加载 
		 * @param loader 要移除的加载器
		 * 
		 */
		private function _removeLoader(loader:LoaderBase):void
		{
			// 查找对应的loader删除
			var key:int = _loaderThreadPool.indexOf(loader);
			loader.Clear();
			loader = null;
			if(key>=0)_loaderThreadPool.splice(key,1);
			
		}
		
		/**
		 * 移除所有加载器 
		 * 
		 */
		private function _removeAllLoader():void
		{
			for each(var loader:LoaderBase in _loaderThreadPool){
				loader.Clear();
			}
			_loaderThreadPool.splice(0,_loaderThreadPool.length);
			
		}
		/**
		 * 删除加载池内的加载信息 
		 * @param resourceObj 加载物信息
		 * @return 
		 * 
		 */
		private function _removeResourceInfo(resourceObj:ResourceObj):void
		{
			// 查找对应信息索引
			var key:int = _loadPool.indexOf(resourceObj);
			if(!key)_loadPool.shift();
			else if(key>0)_loadPool.splice(key-1,1);
			if(key!=-1)trace("移除加载池中的："+resourceObj.url.url);	
			resourceObj = null;		
		}
		/**
		 * 加载加载池的下一个资源
		 * @param currentLoader 当前加载器
		 * 
		 */
		private function _loadNext(currentLoader:LoaderBase=null):void
		{
			// 加载池为0时退出
			if(_loadPool.length==0)return;
			// 判断当前类型
			var info:ResourceObj;
	
			// 判断线程池是否饱和
			if(_loaderThreadPool.length == xLoader.LOADER_MAX_THREAD){
				info =  _loadPool[0] as ResourceObj;
				trace(info.name);
				if(info.name != currentLoader.strLoaderType && currentLoader){
					_removeLoader(currentLoader);
					currentLoader = _addLoader(info.type);
				}
			}else if(_loaderThreadPool.length < xLoader.LOADER_MAX_THREAD){
				info =  _loadPool[0] as ResourceObj;
				trace(info.name);
				currentLoader = _addLoader(info.type);
			}
			if(currentLoader){
				currentLoader.Load(info);
				// 开始载入时删除加载池内的加载信息
				_removeResourceInfo(info);
			} 
		}
	}
}